#include "stdafx.h"
#include "ClientManager.h"


ClientManager::ClientManager(void)
{
	//variables
	m_nState = 0;
	m_cpCpy = m_cCopyBuf;
	m_nDataState = m_kEnum::MLSD;
	m_bCWDfake = false;
	ZeroMemory(m_cUser, sizeof(m_cUser));
	ZeroMemory(m_cPassword, sizeof(m_cPassword));
	ZeroMemory(m_cIP, sizeof(m_cIP));
	ZeroMemory(m_cServPath, sizeof(m_cServPath));
	ZeroMemory(m_cFileName, sizeof(m_cFileName));

	//socket
	WSADATA wsdata;
	if(WSAStartup(MAKEWORD(2,2), &wsdata) != 0)
		ASSERT("WS2_32.DLL Initiate Failed");
	m_nListenfd = socket(AF_INET, SOCK_STREAM, 0);

	//receive
	m_nRecvByte = 0;
	m_nCopyByte = 0;
	m_bRecvError = FALSE;
	ZeroMemory(m_cRecvBuf, sizeof(m_cRecvBuf));
	ZeroMemory(m_cCopyBuf, sizeof(m_cCopyBuf));
}


ClientManager::~ClientManager(void)
{
	// finishing work
}


BOOL ClientManager::Connect(HWND m_hWnd, char *host, char *port)
{
	m_nConnfd = socket(AF_INET, SOCK_STREAM, 0);
	ZeroMemory(&m_kSockaddr, sizeof(m_kSockaddr));
	m_kSockaddr.sin_family = AF_INET;
	m_kSockaddr.sin_addr.s_addr = inet_addr(host);
	m_kSockaddr.sin_port = htons(atoi(port));
	strncpy(m_cIP, host, 16);

	if(connect(m_nConnfd, (SOCKADDR *)&m_kSockaddr, sizeof(m_kSockaddr)) < 0)
	{
		AfxMessageBox("connect() failed");
		int n = GetLastError();
		return FALSE;
	}

	WSAAsyncSelect(m_nConnfd, m_hWnd, WM_USER_SOCKET, FD_READ|FD_CLOSE);

	return TRUE;
}

void ClientManager::Listen(HWND m_hWnd)
{
	ZeroMemory(&m_kSockaddr, sizeof(m_kSockaddr));
	m_kSockaddr.sin_family = AF_INET;
	m_kSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	m_kSockaddr.sin_port = htons(0);

	bind(m_nListenfd, (SOCKADDR *)&m_kSockaddr, sizeof(m_kSockaddr));

	WSAAsyncSelect(m_nListenfd, m_hWnd, WM_USER_SOCKET, FD_ACCEPT|FD_CLOSE);

	if(listen(m_nListenfd, SOMAXCONN))
	{
		AfxMessageBox("Listen Error");
	}
	int len = sizeof(m_kSockaddr);
	getsockname(m_nListenfd, (SOCKADDR *)&m_kSockaddr, &len);
	m_ListenPort = m_kSockaddr.sin_port;
}

int ClientManager::Receive(SOCKET s)
{
again:
	m_bRecvError = FALSE;
	if (m_nRecvByte <= 0)
	{
		if ((m_nRecvByte = recv(s, m_cRecvBuf, SYNBUFSIZE, 0)) <= 0)
		{
			m_bRecvError = TRUE;
			closesocket(s);
		}
		else
			m_cpRecv = m_cRecvBuf;
	}
	if (!m_bRecvError)
	{
		m_cpCopy = m_cCopyBuf;
		for (m_nCopyByte = 1; *m_cpRecv != '\n' && m_nCopyByte < m_nRecvByte; ++m_nCopyByte, ++m_cpRecv, ++m_cpCopy)
		{
			*m_cpCopy = *m_cpRecv;
		}
		*m_cpCopy = *m_cpRecv;
		++m_cpRecv, ++m_cpCopy;
		*m_cpCopy = 0;

		m_nRecvByte -= m_nCopyByte;

		int nResponse = ResponseAnalysis();
		if (nResponse == m_kEnum::DISCONNECT)
		{
			return -1;
		} 
		else if (nResponse == m_kEnum::MLSD || nResponse == m_kEnum::FILEDOWN || nResponse == m_kEnum::FILEUP)
		{
			return nResponse;
		}
		if (m_nRecvByte > 0)
		{
			goto again;
		}
	}
	return 0;
}

void ClientManager::SetState(int state)
{
	m_nState = state;
}

int ClientManager::ResponseAnalysis(void)
{
	m_cpCpy = m_cCopyBuf;

	switch(*m_cpCpy)
	{
	case '1':
		if (m_nState == m_kEnum::CONNECT)
		{
			m_nState = m_kEnum::CONNECT_WAIT;
		}
		return m_kEnum::WAIT;

	case '2':
		if (m_nState == m_kEnum::CONNECT || m_nState == m_kEnum::CONNECT_WAIT)
		{
			send(m_nConnfd, "SYST\r\n", 7, 0);
			m_nState = m_kEnum::SYST;
		}
		else if (m_nState == m_kEnum::SYST)
		{
			if (atoi(m_cpCpy) != 220)
			{
				m_cpCpy += 4;
				if (*m_cpCpy == 'W')
					m_bSameSystem = TRUE;
				else
					m_bSameSystem = FALSE;
				char user[136] = {0,};
				sprintf(user, "USER %s\r\n", m_cUser);
				send(m_nConnfd, user, strlen(user), 0);
				m_nState = m_kEnum::USER;
			}
		}
		else if (m_nState == m_kEnum::USER || m_nState == m_kEnum::PASS)
		{
			send(m_nConnfd, "PWD\r\n", 6, 0);
			m_nState = m_kEnum::PWD;
		}
		else if (m_nState == m_kEnum::PWD)
		{
			m_cpCpy += 5;
			memset(m_cServPath, 0, sizeof(m_cServPath));
			int i;
			for (i = 0; *m_cpCpy != '"'; ++m_cpCpy, ++i)
			{
				m_cServPath[i] = *m_cpCpy;
			}
			if (*m_cpCpy != '/' && strlen(m_cCopyBuf) != 1)
			{
				m_cServPath[i] = '/';
			}
			++i;
			send(m_nConnfd, "PASV\r\n", 7, 0);
			m_nState = m_kEnum::PASV;
		}
		else if (m_nState == m_kEnum::PASV)
		{
			SetDataPort();
			DataRequest(m_nDataState);
			return m_nDataState;
		}
		else if (m_nState == m_kEnum::CWD)
		{
			send(m_nConnfd, "MLSD\r\n", 7, 0);
			m_nState = m_kEnum::NONE;
			return m_kEnum::MLSD;
		}
		return m_kEnum::SUCCESS;

	case '3':
		if (m_nState == m_kEnum::USER)
		{
			char pass[136] = {0,};
			sprintf(pass, "PASS %s\r\n", m_cPassword);
			send(m_nConnfd, pass, strlen(pass), 0);
			m_nState = m_kEnum::PASS;
		}
		return m_kEnum::NEED;

	case '4':
		if (m_nState == m_kEnum::NONE)
			return m_kEnum::DISCONNECT;
		m_nState = 0;
		AfxMessageBox(m_cCopyBuf);
		return m_kEnum::FAILED;

	case '5':
		m_nState = 0;
		AfxMessageBox(m_cCopyBuf);
		return m_kEnum::FAILED;
	}
	return 0;
}

void ClientManager::SetUser(char *user, UINT len)
{
	strncpy(m_cUser, user, len);
}

void ClientManager::SetPassword(char *password, UINT len)
{
	strncpy(m_cPassword, password, len);
}

void ClientManager::SetFileName(char *fn, UINT len)
{
	memset(m_cFileName, 0, sizeof(m_cFileName));
	strncpy(m_cFileName, fn, len);
}

void ClientManager::Close(void)
{
	closesocket(m_nConnfd);
}

void ClientManager::SetDataState(int data)
{
	m_nDataState = data;
}

void ClientManager::SendPWD(void)
{
	send(m_nConnfd, "PWD\r\n", 6, 0);
	m_nState = m_kEnum::PWD;
}

void ClientManager::ChangeDirectory(bool CWD)
{
	send(m_nConnfd, "PWD\r\n", 6, 0);
	m_bCWDfake = true;
	if (CWD)
	{
		m_nDataState = m_kEnum::CWD;
		m_nState = m_kEnum::PWD;
	}
	else 
	{
		m_nDataState = m_kEnum::CDUP;
		m_nState = m_kEnum::CDUP;
	}
}

void ClientManager::DataRequest(int type)
{
	char sendBuf[1024] = {0,};
	m_nState = m_kEnum::NONE;
	if (type == m_kEnum::MLSD)
	{
		sprintf(sendBuf, "MLSD\r\n");
	}
	else if (type == m_kEnum::FILEDOWN)
	{
		sprintf(sendBuf, "RETR %s%s\r\n", m_cServPath, m_cFileName);
	}
	else if (type == m_kEnum::FILEUP)
	{
		sprintf(sendBuf, "STOR %s%s\r\n", m_cServPath, m_cFileName);
	}
	else if (type == m_kEnum::CWD)
	{
		sprintf(sendBuf, "CWD %s%s\r\n", m_cServPath, m_cFileName);
		m_nState = m_kEnum::CWD;
	}
	else if (type == m_kEnum::CDUP )
	{
		sprintf(sendBuf, "CDUP\r\n");
		m_nState = m_kEnum::CWD;
	}
	send(m_nConnfd, sendBuf, strlen(sendBuf), 0);
	m_nDataState = type;
}

void ClientManager::SetDataPort(void)
{
	char port1[4] = {0,};
	char port2[4] = {0,};
	for (int i = 0; i < 4; ++i, ++m_cpCpy)
	{
		m_cpCpy = strchr(m_cpCpy, ',');
	}
	for (int i = 0; *m_cpCpy != ','; ++m_cpCpy, ++i)
	{
		port1[i] = *m_cpCpy;
	}
	++m_cpCpy;
	for (int i = 0; *m_cpCpy != ')'; ++m_cpCpy, ++i)
	{
		port2[i] = *m_cpCpy;
	}
	unsigned short p1 = atoi(port1);
	unsigned short p2 = atoi(port2);
	m_DataPort = p1 * 256 + p2;
}